#ifndef _H_C_NET_SERVICE_IMPL_H_
#define _H_C_NET_SERVICE_IMPL_H_

#include "../typedefine.h"
#include <memory>
#include <vector>
#include <unordered_map>
#include <functional>
#ifdef _WIN32
#include <WinSock2.h>
#include <mutex>
#include "../collection.h"
#include "../timer.h"
#else
#include <sys/epoll.h>
#endif

namespace TB
{
	class CCoroutine;
#ifdef _WIN32
	using DOnNetPollEvent = std::function<void(SOCKET sSocket, SHORT wReturnEvents)>;
#else
	using DOnNetPollEvent = std::function<void(int dwFD, UINT32 dwReturnEvents)>;
#endif

	class CNetServiceImpl
	{
		NON_COPYABLE(CNetServiceImpl)
		NON_MOVEABLE(CNetServiceImpl)
#if !_WIN32
	private:
		static constexpr int MAX_EPOLL_EVENT_COUNT = 1024;
#else
	private:
		class CWsaData
		{
		public:
			CWsaData()
			{
				if (WSAStartup(MAKEWORD(2, 2), &m_oWsaData) != 0)
					throw std::runtime_error("WSAStartup failed");
			}
		private:
			WSADATA m_oWsaData;
		};
#endif
	public:
		CNetServiceImpl();
		~CNetServiceImpl();
		bool Init(const std::weak_ptr<CCoroutine>& roCoroutine, const std::function<void(INT32)>& rcbOnPollError, const std::weak_ptr<CNetServiceImpl>& poSelf);
		void Poll();
#ifdef _WIN32
		bool AddFD(SOCKET sSocket, SHORT wEvents, const DOnNetPollEvent& cbOnPollEvent);
		bool ModFD(SOCKET sSocket, SHORT wEvents);
		bool DelFD(SOCKET sSocket);
#else
		bool AddFD(int dwFD, UINT32 dwEvents, const DOnNetPollEvent& cbOnPollEvent);
		bool ModFD(int dwFD, UINT32 dwEvents);
		bool DelFD(int dwFD);
#endif
		void Close();
		inline std::weak_ptr<CCoroutine>& GetCoroutine() { return m_poCoroutine; }
		inline const std::weak_ptr<CCoroutine>& GetCoroutine() const { return m_poCoroutine; }

	private:
		INT32 _Poll();

	private:
		std::weak_ptr<CCoroutine> m_poCoroutine;
		std::weak_ptr<CNetServiceImpl> m_poSelf;
		std::function<void(INT32)> m_cbOnPollError;
#ifdef _WIN32
		STimerUID m_sTimerUID;
		std::vector<WSAPOLLFD> m_oPollFDSet;
		std::unordered_map<SOCKET, DOnNetPollEvent> m_oPollCallbacks;
		std::vector<WSAPOLLFD> m_oPolledFDCache;
		static CWsaData m_oWsaData;
#else
		int m_nEpollFD = -1;
		UINT64 m_qwPollEventCallbackID = 0;
		epoll_event m_aEpollEvents[MAX_EPOLL_EVENT_COUNT] = {};
		std::unordered_map<int, DOnNetPollEvent> m_oPollCallbacks;
		thread_local static bool m_bInitedEnv;
#endif
	};
}

#endif
